﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Media;
using Microsoft.Windows.Design.PropertyEditing;

namespace DenisVuyka.Controls.PropertyGrid
{
  public class PropertyItemValue : PropertyValue
  {
    private readonly PropertyItem property;

    #region ctor
    public PropertyItemValue(PropertyItem property)
      : base(property)
    {      
      this.property = property;
      this.property.PropertyChanged += new PropertyChangedEventHandler(ParentPropertyChanged);      
    }
    #endregion

    void ParentPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (e.PropertyName == "PropertyValue")
        NotifyRootValueChanged();

      if (e.PropertyName == "IsReadOnly")
      {
        OnPropertyChanged("IsReadOnly");
        OnPropertyChanged("IsEditable");
      }
    }

    #region PropertyValue implementation

    public override bool CanConvertFromString
    {
      get { return (((this.property.Converter != null) && this.property.Converter.CanConvertFrom(typeof(string))) && !this.property.IsReadOnly); }
    }

    public override void ClearValue()
    {
      property.ClearValue();
    }

    // TODO: implement support
    public override PropertyValueCollection Collection
    {
      get { throw new NotImplementedException(); }
    }

    protected override object ConvertStringToValue(string value)
    {
      if (this.property.PropertyType == typeof(string)) return value;
      //if (value.Length == 0) return null;
      if (string.IsNullOrEmpty(value)) return null;
      if (!this.property.Converter.CanConvertFrom(typeof(string)))
        throw new InvalidOperationException("Value to String conversion is not supported!");
      return this.property.Converter.ConvertFromString(null, this.GetSerializationCulture(), value);
    }

    protected override string ConvertValueToString(object value)
    {
      string collectionValue = string.Empty;
      if (value == null) return collectionValue;

      collectionValue = value as String;
      if (collectionValue != null) return collectionValue;

      TypeConverter converter = this.property.Converter;
      if (converter.CanConvertTo(typeof(string)))
        collectionValue = converter.ConvertToString(null, this.GetSerializationCulture(), value);
      else
        collectionValue = value.ToString();

      // TODO: refer to resources or some constant
      if (string.IsNullOrEmpty(collectionValue) && (value is IEnumerable))
        collectionValue = "(Collection)";

      return collectionValue;
    }

    protected override object GetValueCore()
    {
      return this.property.GetValue();
    }

    public override bool HasSubProperties
    {
      get { return false; }
    }

    public override bool IsCollection
    {
      get { return property.IsCollection; }
    }

    public override bool IsDefaultValue
    {
      get { return property.IsDefaultValue; }
    }

    public override bool IsMixedValue
    {
      get { return property.IsMixedValue; }
    }

    protected override void SetValueCore(object value)
    {
      this.property.SetValue(value);
    }

    // TODO: implement support
    public override PropertyValueSource Source
    {
      get { throw new NotImplementedException(); }
    }

    // TODO: implement support
    public override PropertyEntryCollection SubProperties
    {
      get { throw new NotImplementedException(); }
    }

    // TODO: DependencyProperty validation should be placed here
    protected override void ValidateValue(object valueToValidate)
    {
      //throw new NotImplementedException();
      // Do nothing      
    }
    #endregion

    #region Helper properties

    public bool IsReadOnly
    {
      get { return property.IsReadOnly; }
    }

    public bool IsEditable
    {
      get { return !property.IsReadOnly; }
    }

    #endregion

    #region Helpers
    protected virtual CultureInfo GetSerializationCulture()
    {
      CultureInfo currentCulture = CultureInfo.CurrentCulture;
      if ((Array.IndexOf<Type>(PropertyHelper.CultureInvariantTypes, this.property.PropertyType) == -1) && !typeof(Geometry).IsAssignableFrom(this.property.PropertyType))
        return currentCulture;
      return CultureInfo.InvariantCulture;
    }
    #endregion
  }
}
